package com.heima.wemedia.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyuncs.utils.StringUtils;
import com.heima.apis.article.IArticleClient;
import com.heima.article.service.ArticleFreemarkerService;
import com.heima.common.dtos.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.CustomException;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.bean.ContentBean;
import com.heima.wemedia.bean.ImageCheckResult;
import com.heima.wemedia.bean.TextCheckResult;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Resource
    private IArticleClient articleClient;
    @Resource
    private WmNewsMapper wmNewsMapper;
//    private WmNewsService wmNewsService;

    @Resource
    private WmChannelService wmChannelService;
    @Resource
    private WmUserService wmUserService;
    @Resource
    private WmSensitiveService wmSensitiveService;
    @Resource
    private GreenService greenService;
    @Resource
    private ArticleFreemarkerService articleFreemarkerService;
    @Resource
    private OCRService ocrService;

    private static final int CONTENT_TEXT = 1;
    private static final int CONTENT_IMAGE = 2;


    @Override
    @Async
    public void autoScanWmNews(Integer id) {
        WmNews wmNews = wmNewsMapper.selectById(id);
//        WmNews wmNews = wmNewsService.getById(id);
        // 判断文章是否存在
        if (ObjectUtil.isEmpty(wmNews)){
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 判断文章内容是否为空，为空直接返回true
        if (ObjectUtil.isEmpty(wmNews.getContent())){
            return;
        }

        // 提取文章文本内容
        List<String> textList = this.extractTextOrImage(wmNews, CONTENT_TEXT);
        // 审核文本内容
        Boolean handleText = this.handleText(wmNews, textList);
        if (!handleText){
            return;
        }
        // 提取文章图片内容
        List<String> images = this.extractTextOrImage(wmNews, CONTENT_IMAGE);
        // 审核图片内容
        Boolean handleImage = this.handleImage(wmNews, images);
        if (!handleImage){
            return;
        }

        // 审核通过，发布文章
        ArticleDto articleDto = BeanUtil.toBean(wmNews, ArticleDto.class);
        //文章的布局
        articleDto.setLayout(wmNews.getType());
        // 文章作者的名字
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        articleDto.setAuthorId(Convert.toLong(wmNews.getUserId()));
        if (ObjectUtil.isNotEmpty(wmUser)){
            articleDto.setAuthorName(wmUser.getName());
        }
        // 获取频道信息
        WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
        if (ObjectUtil.isNotEmpty(wmChannel)){
            articleDto.setChannelName(wmChannel.getName());
        }
        // 设置id
        articleDto.setId(wmNews.getArticleId());

        articleDto.setCreatedTime(new Date());

        ResponseResult<Long> longResponseResult = articleClient.saveArticle(articleDto);
        if (!ObjectUtil.equals(longResponseResult.getCode(), 200)){
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }

        wmNews.setArticleId(longResponseResult.getData());
        articleFreemarkerService.buildArticleToMinIO(BeanUtil.toBean(articleDto, ApArticle.class), articleDto.getContent());
        updateWmNews(wmNews, WmNews.Status.PUBLISHED, "审核成功");
    }

    /**
     *  审核图片内容
     * @param wmNews 文章对象
     * @param imageList 文本图片集合
     * @return
     */
    private Boolean handleImage(WmNews wmNews, List<String> imageList){

        if (ObjectUtil.isEmpty(imageList)){
            return true;
        }
        for (String image : imageList) {
            try {
                URL url = new URL(image);
                BufferedImage bufferedImage = ImageIO.read(url);
                String doneORC = this.ocrService.doORC(bufferedImage);
                Boolean handled = this.handleSensitive(doneORC, wmNews);
                if (!handled){
                    return false;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            ImageCheckResult imageCheckResult = greenService.imageCheck(image);
            String riskLevel = imageCheckResult.getRiskLevel();
            if (ObjectUtil.equals(riskLevel, "high")){
                String reason = StrUtil.format("当前文章中存在违规内容，风险等级为：{}，风险描述为：{}",
                        riskLevel,
                        StrUtil.join("|", imageCheckResult.getDescriptionList()));
                updateWmNews(wmNews, WmNews.Status.FAIL, reason);
                return false;
            }
            if (ObjectUtil.emptyCount(riskLevel, "medium", "low", "null") > 0){
                String reason = StrUtil.format("当前文章中存在不确定内容，风险等级为：{}，风险描述为：{}",
                        riskLevel,
                        StrUtil.join("|", imageCheckResult.getDescriptionList()));
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH, reason);
                return false;
            }
        }
        return true;
    }

    private Boolean handleSensitive(String content, WmNews wmNews){
        // 查询敏感词汇对象列表
        List<WmSensitive> wmSensitives = wmSensitiveService.list();
        List<String> wmSensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        SensitiveWordUtil.initMap(wmSensitiveList);

        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(content);
        if (ObjectUtil.isNotEmpty(matchWords)){
            List<String> stringList = matchWords.entrySet().stream().map(sensitiveWords -> StrUtil.format("【{}】，出现了【{}】次", sensitiveWords.getKey(), sensitiveWords.getValue()))
                    .collect(Collectors.toList());
            String reason = StrUtil.format("当前文章中存在违规内容，风险等级为：高风险，风险词为：{}",
                    StrUtil.join(",", stringList));
            updateWmNews(wmNews, WmNews.Status.FAIL, reason);
            return false;
        }
        return true;
    }

    /**
     *  审核文本内容
     * @param wmNews 文章对象
     * @param textList 文本内容集合
     * @return
     */
    private Boolean handleText(WmNews wmNews, List<String> textList){
        String content = StrUtil.join(",", textList);
        Boolean sensitive = this.handleSensitive(content, wmNews);
        if (!sensitive){
            return false;
        }
        TextCheckResult textCheckResult = greenService.textCheck(StrUtil.join(" ", textList));
        String riskLevel = textCheckResult.getRiskLevel();
        if (ObjectUtil.equals(riskLevel, "none")){
            return true;
        }

        if (ObjectUtil.equals(riskLevel, "high")){
            String reason = StrUtil.format("当前文章中存在违规内容，风险等级为：{}，风险词为：{}",
                    riskLevel,
                    StrUtil.join("|", textCheckResult.getRiskWordsList()));
            updateWmNews(wmNews, WmNews.Status.FAIL, reason);
            return false;
        }
        if (ObjectUtil.emptyCount(riskLevel, "medium", "low", "null") > 0){
            String reason = StrUtil.format("当前文章中存在不确定内容，风险等级为：{}，风险词为：{}",
                    riskLevel,
                    StrUtil.join("|", textCheckResult.getRiskWordsList()));
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH, reason);
            return false;
        }
        return false;
    }

    /**
     *  更新文章信息
     * @param wmNews 文章对象
     * @param status  文章状态
     * @param reason   文章审核结果原因
     */
    private void updateWmNews(WmNews wmNews, WmNews.Status status, String reason){
        wmNews.setStatus(status.getCode());
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
//        wmNewsService.updateById(wmNews);
    }

    /**
     *   提取文章的文本内容和图片内容
     * @param wmNews 文章对象
     * @param type  内容的类型
     * @return
     */
    private List<String> extractTextOrImage(WmNews wmNews, int type){
        List<String> result = new ArrayList<>();
        String content = wmNews.getContent();
        List<ContentBean> list = JSONUtil.toList(content, ContentBean.class);
        List<ContentBean> contentBeans = CollStreamUtil.toList(list, contentBean -> {
            if (type == 1) {
                if (ObjectUtil.equals(contentBean.getType(), "text")) {
                    result.add(contentBean.getValue());
                }
            }
            if (type == 2) {
                if (ObjectUtil.equals(contentBean.getType(), "image")) {
                    result.add(contentBean.getValue());
                }
            }
            return contentBean;
        });
        if (type == 1){
            result.add(wmNews.getTitle());
        } else {
            CollUtil.addAll(result, StrUtil.split(wmNews.getImages(), ","));
        }
        return result;
    }


}
